"""
混合调度器
结合NSGA-II、WOA和DQN的混合优化调度器
"""

from typing import List, Dict, Any, Tuple
import numpy as np
from datetime import datetime
from .base_scheduler import BaseScheduler
from .nsga2_scheduler import NSGA2Scheduler
from .woa_scheduler import WOAScheduler
from .dqn_scheduler import DQNScheduler

class HybridScheduler(BaseScheduler):
    """混合调度器"""
    
    def __init__(self, config: Dict[str, Any] = None):
        super().__init__(config)
        
        # 初始化子调度器
        self.nsga2_scheduler = NSGA2Scheduler(config.get('nsga2', {}))
        self.woa_scheduler = WOAScheduler(config.get('woa', {}))
        self.dqn_scheduler = DQNScheduler(config.get('dqn', {}))
        
        # 混合策略配置
        self.global_search_ratio = config.get('global_search_ratio', 0.6)
        self.local_search_ratio = config.get('local_search_ratio', 0.3)
        self.real_time_ratio = config.get('real_time_ratio', 0.1)
        
    def optimize(self, 
                 resources: List[Dict], 
                 appointments: List[Dict], 
                 objectives: List[str]) -> Dict[str, Any]:
        """
        执行混合优化
        
        Args:
            resources: 资源列表
            appointments: 预约列表
            objectives: 优化目标列表
            
        Returns:
            调度结果字典
        """
        self.resources = resources
        self.appointments = appointments
        
        # 第一阶段：全局搜索（NSGA-II）
        print("执行全局搜索...")
        global_result = self.nsga2_scheduler.optimize(resources, appointments, objectives)
        global_solution = global_result['solution']
        
        # 第二阶段：局部优化（WOA）
        print("执行局部优化...")
        local_result = self.woa_scheduler.optimize(resources, appointments, objectives)
        local_solution = local_result['solution']
        
        # 第三阶段：实时微调（DQN）
        print("执行实时微调...")
        realtime_result = self.dqn_scheduler.optimize(resources, appointments, objectives)
        realtime_solution = realtime_result['solution']
        
        # 混合解决方案
        final_solution = self._hybrid_solutions(
            global_solution, 
            local_solution, 
            realtime_solution
        )
        
        # 计算最终目标值
        final_objectives = self.calculate_objectives(final_solution)
        
        return {
            'solution': final_solution,
            'objectives': final_objectives,
            'algorithm': 'Hybrid',
            'global_result': global_result,
            'local_result': local_result,
            'realtime_result': realtime_result,
            'improvement': self._calculate_improvement(
                global_result['objectives'],
                final_objectives
            )
        }
    
    def _hybrid_solutions(self, 
                         global_solution: Dict[str, Any], 
                         local_solution: Dict[str, Any], 
                         realtime_solution: Dict[str, Any]) -> Dict[str, Any]:
        """混合多个解决方案"""
        hybrid_assignments = {}
        
        # 获取所有资源ID
        all_resource_ids = set()
        for solution in [global_solution, local_solution, realtime_solution]:
            all_resource_ids.update(solution.get('assignments', {}).keys())
        
        # 为每个资源选择最佳分配
        for resource_id in all_resource_ids:
            candidates = []
            
            # 收集各算法的分配方案
            if resource_id in global_solution.get('assignments', {}):
                candidates.append(('global', global_solution['assignments'][resource_id]))
            if resource_id in local_solution.get('assignments', {}):
                candidates.append(('local', local_solution['assignments'][resource_id]))
            if resource_id in realtime_solution.get('assignments', {}):
                candidates.append(('realtime', realtime_solution['assignments'][resource_id]))
            
            # 选择最佳分配
            if candidates:
                best_assignment = self._select_best_assignment(candidates)
                hybrid_assignments[resource_id] = best_assignment
        
        return {'assignments': hybrid_assignments}
    
    def _select_best_assignment(self, candidates: List[Tuple[str, List[Dict]]]) -> List[Dict]:
        """选择最佳资源分配"""
        best_score = float('inf')
        best_assignment = None
        
        for algorithm, assignment in candidates:
            # 计算分配质量评分
            score = self._evaluate_assignment_quality(assignment)
            
            if score < best_score:
                best_score = score
                best_assignment = assignment
                
        return best_assignment or candidates[0][1]
    
    def _evaluate_assignment_quality(self, assignment: List[Dict]) -> float:
        """评估分配质量"""
        if not assignment:
            return float('inf')
        
        # 计算时间利用率
        total_duration = sum(
            (a['end_time'] - a['start_time']).total_seconds() / 3600
            for a in assignment
        )
        
        # 计算时间冲突
        conflicts = self._count_time_conflicts(assignment)
        
        # 综合评分（越小越好）
        score = conflicts * 10 + (1 / (total_duration + 1))
        return score
    
    def _count_time_conflicts(self, assignment: List[Dict]) -> int:
        """计算时间冲突数量"""
        if len(assignment) <= 1:
            return 0
        
        # 按开始时间排序
        sorted_assignment = sorted(assignment, key=lambda x: x['start_time'])
        conflicts = 0
        
        for i in range(len(sorted_assignment) - 1):
            current = sorted_assignment[i]
            next_assignment = sorted_assignment[i + 1]
            
            if current['end_time'] > next_assignment['start_time']:
                conflicts += 1
                
        return conflicts
    
    def _calculate_improvement(self, 
                             initial_objectives: Dict[str, float], 
                             final_objectives: Dict[str, float]) -> Dict[str, float]:
        """计算改进程度"""
        improvement = {}
        
        for key in initial_objectives:
            if key in final_objectives:
                initial_val = initial_objectives[key]
                final_val = final_objectives[key]
                
                if initial_val != 0:
                    improvement[key] = ((final_val - initial_val) / initial_val) * 100
                else:
                    improvement[key] = 0
                    
        return improvement
    
    def optimize_real_time(self, 
                          new_appointment: Dict, 
                          current_solution: Dict[str, Any]) -> Dict[str, Any]:
        """实时优化新预约"""
        # 使用DQN进行实时调度
        resources = self.resources
        appointments = [new_appointment]
        
        # 考虑当前解决方案的约束
        constrained_resources = self._apply_current_constraints(current_solution)
        
        result = self.dqn_scheduler.optimize(constrained_resources, appointments, [])
        
        return result
    
    def _apply_current_constraints(self, current_solution: Dict[str, Any]) -> List[Dict]:
        """应用当前解决方案的约束"""
        constrained_resources = []
        
        for resource in self.resources:
            # 检查资源是否已被占用
            if resource['id'] in current_solution.get('assignments', {}):
                # 创建约束版本
                constrained_resource = resource.copy()
                constrained_resource['status'] = 'occupied'
                constrained_resources.append(constrained_resource)
            else:
                constrained_resources.append(resource)
                
        return constrained_resources
